package com.qs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qs.constant.GoodsConstant;
import com.qs.constant.RedisConstant;
import com.qs.constant.StatusConstant;
import com.qs.exception.ServiceException;
import com.qs.mapper.CategoryMapper;
import com.qs.mapper.StoreMapper;
import com.qs.pojo.dto.AdminDto;
import com.qs.pojo.dto.BrandDto;
import com.qs.pojo.dto.GoodsDto;
import com.qs.pojo.dto.UserDto;
import com.qs.pojo.entity.Admin;
import com.qs.pojo.entity.Brand;
import com.qs.mapper.BrandMapper;
import com.qs.pojo.entity.Category;
import com.qs.pojo.entity.Store;
import com.qs.response.ResponseEnum;
import com.qs.service.IBrandService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qs.utils.LockUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 品牌管理表 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-11-12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BrandServiceImpl extends ServiceImpl<BrandMapper, Brand> implements IBrandService {

    private final BrandMapper brandMapper;

    private final CategoryMapper categoryMapper;

    private final StoreMapper storeMapper;

    private final RedisTemplate redisTemplate;

    @Override
    public Map<String, Object> getList(Integer pageNo, Integer pageSize, String name) {
        //去除前后空白
        String trimName = name.trim();
        Page<Brand> pageInfo = new Page<>(pageNo,pageSize);
        QueryWrapper<Brand> wrapper = new QueryWrapper<>();
        /**
         * 根据用户名进行模糊查询
         */
        wrapper.eq(!StringUtils.isBlank(trimName),"name",trimName);
        wrapper.orderByDesc("update_time");
        Page<Brand> brandPage = baseMapper.selectPage(pageInfo, wrapper);
        if(null != brandPage) {
            //进行数据转换
            List<Brand> records = brandPage.getRecords();
            if(!CollectionUtils.isEmpty(records)) {
                List<BrandDto> brandDtoList = new ArrayList<>();
                records.stream().forEach(item -> {
                    BrandDto brandDto = new BrandDto();
                    BeanUtils.copyProperties(item,brandDto);
                    brandDto.setKey(item.getId());
                    brandDtoList.add(brandDto);
                });
                Map<String,Object> map = new HashMap<>();
                map.put("data",brandDtoList);
                map.put("total",brandPage.getTotal());
                return map;
            }
        }
        return null;
    }

    @Override
    public void updateByKey(BrandDto brandDto) {
        Brand brand = new Brand();
        BeanUtils.copyProperties(brandDto,brand);
        brand.setId(brandDto.getKey());
        baseMapper.updateById(brand);
        redisTemplate.delete(RedisConstant.GOODS_BRAND);
    }

    @Override
    public BrandDto echo(Integer id) {
        if(null != id){
            Brand brand = baseMapper.selectById(id);
            BrandDto brandDto = new BrandDto();
            BeanUtils.copyProperties(brand,brandDto);
            brandDto.setKey(brand.getId());
            return brandDto;
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> getBrandList() {
        try {
            List<Map<String, Object>> brandsMap = (List<Map<String, Object>>) redisTemplate.opsForValue().get(RedisConstant.GOODS_BRAND);
            if(!CollectionUtils.isEmpty(brandsMap)){
                log.info("品牌命中了redis缓存");
                return brandsMap;
            }else{
                String lockKey = RedisConstant.GOODS_BRAND_LOCK;
                boolean isLock = LockUtils.tryLock(lockKey,"brand");
                if(!isLock){
                    //未获取到锁,休眠一段时间等待前一个线程重建缓存
                    Thread.sleep(RedisConstant.THREAD_SLEEP);
                    //重新获取,递归
                    return getBrandList();
                }
                //获取到了锁
                //再去redis中查询是否有缓存的数据
                List<Map<String, Object>> brandMap = (List<Map<String, Object>>) redisTemplate.opsForValue().get(RedisConstant.GOODS_BRAND);
                if(!CollectionUtils.isEmpty(brandMap)){
                    log.info("品牌命中了redis缓存");
                    return brandMap;
                }
                List<Brand> brandList = brandMapper.selectList(null);
                List<Map<String, Object>> list = new ArrayList<>();
                if(CollectionUtils.isEmpty(brandList)){
                    //如果数据中不存在则缓存空对象返回来解决redis缓存穿透,两分钟后过期
                    Map<String,Object> map = new HashMap<>(1);
                    map.put("value","");
                    map.put("label","");
                    list.add(map);
                    redisTemplate.opsForValue().set(RedisConstant.GOODS_BRAND,list,RedisConstant.CACHE_NULL_EXPIRE, TimeUnit.MINUTES);
                }else{
                    //进行缓存重建
                    brandList.stream().forEach(brand -> {
                        Map<String,Object> map = new HashMap<>(brandList.size());
                        map.put("value",brand.getName());
                        map.put("label",brand.getName());
                        list.add(map);
                    });
                    redisTemplate.opsForValue().set(RedisConstant.GOODS_BRAND,list,RedisConstant.CACHE_EXPIRE,TimeUnit.MINUTES);
                    return list;
                }
            }
        }catch (Exception e){
            throw new ServiceException(ResponseEnum.ERROR);
        }finally {
            LockUtils.unLock(RedisConstant.GOODS_BRAND_LOCK);
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> getCategory() {
        List<Map<String, Object>> categorysList = (List<Map<String, Object>>) redisTemplate.opsForValue().get(RedisConstant.GOODS_CATEGORY);
        if(!CollectionUtils.isEmpty(categorysList)){
            log.info("商品分类成功命中redis缓存-------------------");
            return categorysList;
        }else{
            String lockKey = RedisConstant.GOODS_CATEGORY_LOCK;
            try {
                boolean isLock = LockUtils.tryLock(lockKey, "category");
                if(!isLock){
                    Thread.sleep(RedisConstant.THREAD_SLEEP);
                    return getCategory();
                }
                //再去redis中查询是否有缓存的数据
                List<Map<String, Object>> categoryLists = (List<Map<String, Object>>) redisTemplate.opsForValue().get(RedisConstant.GOODS_CATEGORY);
                if(!CollectionUtils.isEmpty(categoryLists)){
                    log.info("商品分类成功命中redis缓存-------------------");
                    return categoryLists;
                }
                //只需查询二级分类即可，一级分类自然就知道
                List<Category> categories = categoryMapper.selectList(null);
                List<Map<String, Object>> list = new ArrayList<>();
                if(CollectionUtils.isEmpty(categories)){
                    //如果数据中不存在则缓存空对象返回来解决redis缓存穿透,两分钟后过期
                    Map<String,Object> map = new HashMap<>(1);
                    map.put("value","");
                    map.put("label","");
                    list.add(map);
                    redisTemplate.opsForValue().set(RedisConstant.GOODS_CATEGORY,list,RedisConstant.CACHE_NULL_EXPIRE, TimeUnit.MINUTES);
                }else{
                    //缓存重建
                    //过滤出二级分类
                    List<Category> categoryList = categories.stream().filter(category -> category.getPid() != 0).collect(Collectors.toList());
                    categoryList.stream().forEach(category -> {
                        Map<String,Object> map = new HashMap<>(categoryList.size());
                        map.put("value",category.getName());
                        map.put("label",category.getName());
                        list.add(map);
                    });
                    redisTemplate.opsForValue().set(RedisConstant.GOODS_CATEGORY,list,RedisConstant.CACHE_EXPIRE,TimeUnit.MINUTES);
                    return list;
                }
            }catch (Exception e) {
                throw new ServiceException(ResponseEnum.ERROR);
            }finally {
                LockUtils.unLock(lockKey);
            }
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> getStores(Integer userId) {
        List<Map<String, Object>> storeList = (List<Map<String, Object>>) redisTemplate.opsForValue().get(RedisConstant.USER_STORE + userId);
        if(!CollectionUtils.isEmpty(storeList)){
            log.info("用户所属的店铺数据命中redis缓存---------");
            return storeList;
        }else{
            QueryWrapper<Store> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id",userId);
            //只查询审核通过的店铺
            wrapper.eq("status",StatusConstant.STATUS_STORE_PASS);
            List<Store> stores = storeMapper.selectList(wrapper);
            List<Map<String, Object>> list = new ArrayList<>();
            stores.stream().forEach(store -> {
                Map<String,Object> map = new HashMap<>(stores.size());
                map.put("id",store.getId());
                map.put("value",store.getHomeName());
                map.put("label",store.getHomeName());
                list.add(map);
            });
            if(!CollectionUtils.isEmpty(list)){
                redisTemplate.opsForValue().set(RedisConstant.USER_STORE + userId,list,RedisConstant.CACHE_EXPIRE,TimeUnit.MINUTES);
                return list;
            }
            return null;
        }
    }

    @Override
    public void saveBrand(Brand brand) {
        QueryWrapper<Brand> wrapper = new QueryWrapper<>();
        wrapper.eq("name", brand.getName());
        Brand selectOne = baseMapper.selectOne(wrapper);
        if(null != selectOne){
            throw new ServiceException(ResponseEnum.BRAND_EXITS);
        }
        baseMapper.insert(brand);
        //将缓存数据删除
        redisTemplate.delete(RedisConstant.GOODS_BRAND);
    }

    @Override
    public void delete(List<Integer> ids) {
        baseMapper.deleteBatchIds(ids);
        redisTemplate.delete(RedisConstant.GOODS_BRAND);
    }
}
